#pragma once
#include"MY_API.hpp"
#include"mysql_module.hpp"
#include"online_manage_module.hpp"
#include"match_manage_module.hpp"
#include"room_manage_module.hpp"
#include"session_manage_module.hpp"
#include"Ai_Robot.hpp"

#define WWWROOT "./wwwroot"
#define NOT_FOUND "./wwwroot/not_found.html"
#define STOP_BROKEN_LINK 60000

class web_server{
private:
    std::string _wwwroot;
    user_table _web_ut;
    online_manage _web_om;
    room_manage _web_rm;
    session_manage _web_sm;
    match_manage _web_mm;
    web_server_t _web_ser;
public:
    web_server(std::string host, std::string user_name, std::string passwd, std::string db,\
    unsigned int port, const std::string &wwwroot = WWWROOT)
    :_wwwroot(wwwroot),_web_ut(host, user_name, passwd, db, port), _web_rm(&_web_ut, &_web_om),
    _web_sm(&_web_ser), _web_mm(&_web_rm, &_web_ut, &_web_om)
    {
        //设置日志等级
        _web_ser.set_access_channels(websocketpp::log::alevel::none);

        //初始化asio框架调度器
        _web_ser.init_asio();

        //允许地址重用
        _web_ser.set_reuse_addr(true);

        //设置业务处理回调函数
        _web_ser.set_http_handler(std::bind(&web_server::web_http_callback, this, std::placeholders::_1));
        _web_ser.set_open_handler(std::bind(&web_server::web_open_callback, this, std::placeholders::_1));
        _web_ser.set_message_handler(std::bind(&web_server::web_message_callback, this, std::placeholders::_1, std::placeholders::_2));
        _web_ser.set_close_handler(std::bind(&web_server::web_close_callback, this, std::placeholders::_1));
    }

    ~web_server(){}

    void destory_or_reconnection(int uid)
    {
        if (_web_om.is_in_room(uid) == false)
        {
            _web_rm.remove_room_user(uid);
            //std::cout<< "用户从游戏房间中退出了" << std::endl;
        }

        //std::cout << "用户刷新了，重连成功" << std::endl;
    }

    void join_robot_to_match_queue()
    {
        if (_web_mm.get_normal_queue_size() == 1)
        {
            web_server_t::connection_ptr tmp;
            _web_om.enter_hall(-1, tmp);
            _web_mm.add(-1);
        }
    }

    void sendmsg_to_mysql()
    {
        _web_ut.prevent_link_broken();
    }

    void stop_broken_link_mysqld()
    {
        while(true)
        {
            web_server_t::timer_ptr tmp = _web_ser.set_timer(STOP_BROKEN_LINK, \
            std::bind(&web_server::sendmsg_to_mysql, this));
            sleep(1800);
        }
    }

    void web_server_start(uint16_t port)
    {
        //设置服务器监听端口
        _web_ser.listen(port);

        //开始获取新连接
        _web_ser.start_accept();

        //定时向MySQL服务器发送消息，防止链接断开（半小时发一次）
        std::thread mysqld_heart(&web_server::stop_broken_link_mysqld, this);

        //启动服务器
        _web_ser.run();
    }

private:
    void http_resp(web_server_t::connection_ptr conn, bool result, \
    websocketpp::http::status_code::value rcode, std::string reason)
    {
        std::string resp_error_msg;
        Json::Value error_json;
        error_json["result"] = result;
        error_json["reason"] = reason;
        Json_API::serialize(error_json, resp_error_msg);
        //std::cout << resp_error_msg << "  "<< error_json["reason"].asString() << std::endl;
        conn->set_status(rcode);
        conn->set_body(resp_error_msg);
        conn->append_header("Content-Type", "application/json");
    }

    //请求文件处理模块
    void file_handle(web_server_t::connection_ptr conn)
    {
        websocketpp::http::parser::request req = conn->get_request();
        std::string uri_path = req.get_uri();
        //std::cout << uri_path << std::endl;
        std::string real_path = WWWROOT + uri_path;

        if(real_path.back() == '/')
        {
            real_path += "login.html";
        }

        std::string body;
        if (!File_API::read_file(real_path, body))
        {
            File_API::read_file(NOT_FOUND, body);
            conn->set_body(body);
            conn->set_status(websocketpp::http::status_code::not_found);
            return;           
        }
        conn->set_body(body);
        conn->set_status(websocketpp::http::status_code::ok);
    }


 //用户注册处理模块
    void user_register(web_server_t::connection_ptr conn)
    {
        //log_message(ERROR, "收到注册请求");
        websocketpp::http::parser::request req = conn->get_request();
        //1. 获取到请求正文
        std::string req_body = conn->get_request_body();
        //2. 对正文进行json反序列化，得到用户名和密码
        Json::Value user_msg;
        bool check = Json_API::deserialize(req_body, user_msg);
        if (check == false)
        {
            return http_resp(conn, false, websocketpp::http::status_code::ok,"请求的信息有误");
        }

        //3. 进行数据库的用户新增操作
         //先查找数据库中有没有该用户
         if (user_msg["password"].isNull())
         {
            log_message(ERROR, "用户没有输入密码");
            //std::cout << "用户没有输入密码" << std::endl;
         }
         std::cout << user_msg["password"].isNull() << std::endl;


         if (user_msg["username"].isNull() || user_msg["password"].isNull())
         {
            log_message(ERROR, "用户名或密码有误，请重新输入");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"用户名或密码有误，请重新输入");
         }

         if(_web_ut.select_by_name(user_msg["username"].asString(), user_msg))
         {
            log_message(ERROR, "该用户名已被占用，请重新输入");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"该用户名已被占用，请重新输入");
         }

         if (!_web_ut.insert_user(user_msg))
         {
            log_message(ERROR, "密码强度太低");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"密码强度太低");
         }

        //  如果成功了，则返回200
        return http_resp(conn, true , websocketpp::http::status_code::ok,"用户创建成功");
    }


    //用户登录处理模块
    void user_login(web_server_t::connection_ptr conn)
    {
        //log_message(ERROR, "收到登录请求");
        websocketpp::http::parser::request req = conn->get_request();
        //1. 获取到请求正文
        std::string req_body = conn->get_request_body();
        //2. 对正文进行json反序列化，得到用户名和密码
        Json::Value user_msg;
        bool check = Json_API::deserialize(req_body, user_msg);
        if (check == false)
        {
            log_message(ERROR, "登录请求的信息有误");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"请求的信息有误");
        }

        //std::cout << user_msg["username"].asString() << "  "<< user_msg["password"].asString() << std::endl;
        //3. 在数据库中对比该用户是否存在
         //先查找数据库中有没有该用户
        if (user_msg["username"].isNull() || user_msg["password"].isNull())
        {
            log_message(ERROR, "登录用户名或密码有误，请重新输入");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"用户名或密码有误，请重新输入");
        }

        if (!_web_ut.login(user_msg))
        {
            log_message(ERROR, "登录失败，请重新输入");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"登录信息有误，请重新输入");
        }

         //如果验证成功，给客户端创建session
        int uid = user_msg["id"].asInt();
        session_ptr sp = _web_sm.create_session(uid, LOGIN);
        if (sp.get() == nullptr)
        {
            log_message(ERROR, "创建会话失败");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"创建会话失败");
        }
        
        sp->set_user(uid);
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_TIMEOUT);

        //设置响应头部：Set-Cookie,将sessionid通过cookie返回
        std::string cookie_ssid = "SSID=" + std::to_string(sp->get_ssid());
        conn->append_header("Set-Cookie", cookie_ssid);

        return http_resp(conn, true , websocketpp::http::status_code::ok,"登录成功");     
    }

    bool get_ssid_from_cookie(const std::string& req_body, const std::string &key,  std::string &val)
    {
        std::vector<std::string> req_section;
        String_API::string_split(req_body, "; ", req_section);

        for (int i = 0; i < req_section.size(); i++)
        {
            std::vector<std::string> tmp_section;
            if (String_API::string_split(req_section[i], "=", tmp_section) < 2)
            {
                continue;
            }

            if (tmp_section[0] == key)
            {
                val = tmp_section[1];
                return true;
            }
        }
        return false;
    }

    session_ptr get_session_ptr_from_connect_http(web_server_t::connection_ptr conn)
    {
        websocketpp::http::parser::request req = conn->get_request();
        std::string cookie_req = conn->get_request_header("Cookie");
        // 1. 获取请求信息中的Cookie，从Cookie中获取ssid
        if (cookie_req.empty())
        {  
            http_resp(conn, false, websocketpp::http::status_code::ok, "找不到cookie信息，请重新登录");
            return session_ptr();
        }     
        // 1.5. 从cookie中取出ssid
        std::string ssid_str;
        if (!get_ssid_from_cookie(cookie_req, "SSID", ssid_str))
        {
            http_resp(conn, false, websocketpp::http::status_code::ok, "找不到session信息，请重新登录");
            return session_ptr();
        }
        // 2. 在session管理中查找对应的会话信息
        session_ptr sp = _web_sm.get_session_by_ssid(std::stol(ssid_str));
        if (sp.get() == nullptr)
        {
            http_resp(conn, false, websocketpp::http::status_code::ok, "session信息已过期，请重新登录");
            return session_ptr();
        }   

        return sp;
    }
    
    //获取用户信息处理模块
    void user_info(web_server_t::connection_ptr conn)
    {
        //log_message(ERROR, "收到用户信息查询请求");
        Json::Value resp;
        
        session_ptr sp = get_session_ptr_from_connect_http(conn);
        if (sp.get() == nullptr)
            return;
        // 3. 从数据库中取出用户信息，进行序列化发送给客户端
        if (_web_ut.select_by_id(sp->get_user(), resp) == false)
        {
            log_message(ERROR, "找不到用户信息，请重新登录");
            return http_resp(conn, false, websocketpp::http::status_code::ok, "找不到用户信息，请重新登录");
        }

        resp["result"] = true;
        std::string resp_msg;
        Json_API::serialize(resp, resp_msg);
        conn->set_body(resp_msg);
        conn->append_header("Content-Type", "application/json");
        conn->set_status(websocketpp::http::status_code::ok);
        // 4. 刷新session的过期时间
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_TIMEOUT);
    }

    void rank_list(web_server_t::connection_ptr conn)
    {
        //log_message(ERROR, "收到排行榜查询请求");
        websocketpp::http::parser::request req = conn->get_request();
        std::string cookie_req = conn->get_request_header("Cookie");
        Json::Value resp;
        
        session_ptr sp = get_session_ptr_from_connect_http(conn);
        if (sp.get() == nullptr)
            return;

        // 3. 从数据库中取出用户信息，进行序列化发送给客户端
        if (_web_ut.select_rank_by_id(sp->get_user(), resp) == false)
        {
            log_message(ERROR, "找不到用户信息，请重新登录");
            return http_resp(conn, false, websocketpp::http::status_code::ok, "找不到用户信息，请重新登录");
        }

        resp["result"] = true;
        std::string resp_msg;
        Json_API::serialize(resp, resp_msg);
        conn->set_body(resp_msg);
        conn->append_header("Content-Type", "application/json");
        conn->set_status(websocketpp::http::status_code::ok);
    }

    void viewer_info(web_server_t::connection_ptr conn)
    {
        //log_message(ERROR, "收到观战查询请求");
        websocketpp::http::parser::request req = conn->get_request();
        std::string cookie_req = conn->get_request_header("Cookie");
        Json::Value resp;

        session_ptr sp = get_session_ptr_from_connect_http(conn);
        if (sp.get() == nullptr)
            return;

        std::string req_body = conn->get_request_body();
        //2. 对正文进行json反序列化，得到房间号

        Json::Value room_msg;
        bool check = Json_API::deserialize(req_body, room_msg);
        if (check == false)
        {
            log_message(ERROR, "房间信息有误");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"房间信息有误");
        }

        //std::cout << req_body << std::endl;
        //查找用户观战的游戏房间是否存在，若存在，游戏是否已经结束
        std::string room_id_str = room_msg["room_id"].asString();

        uint64_t room_id = atoll(room_id_str.c_str());
        
        //std::cout << "观战用户要查找的房间号为  " << room_id << std::endl;
        room_ptr rp = _web_rm.get_room_by_roomid(room_id);
        if (rp.get() == nullptr)
        {
            log_message(ERROR, "游戏房间不存在");
            return http_resp(conn, false, websocketpp::http::status_code::ok, "游戏房间不存在");
        }

        if (rp->get_room_status() == game_over)
        {
            log_message(ERROR, "该房间游戏已结束");
            return http_resp(conn, false, websocketpp::http::status_code::ok, "该房间游戏已结束");
        }

        //获取用户id，将用户添加到他要观战的房间中，并让用户加入房间
        int uid = sp->get_user();
        rp->add_viewer(uid);
        _web_rm.add_viewer_users(uid, room_id);

        resp["result"] = true;
        std::string resp_msg;
        Json_API::serialize(resp, resp_msg);
        conn->set_body(resp_msg);
        conn->append_header("Content-Type", "application/json");
        conn->set_status(websocketpp::http::status_code::ok);
    }

    void replay_info(web_server_t::connection_ptr conn)
    {
        //log_message(NORMAL, "收到棋局复盘请求");
        websocketpp::http::parser::request req = conn->get_request();
        std::string cookie_req = conn->get_request_header("Cookie");
        Json::Value resp;

        session_ptr sp = get_session_ptr_from_connect_http(conn);
        if (sp.get() == nullptr)
            return;

        std::string req_body = conn->get_request_body();
        //2. 对正文进行json反序列化，得到场次号

        Json::Value fight_msg;
        bool check = Json_API::deserialize(req_body, fight_msg);
        if (check == false)
        {
            log_message(ERROR, "场次信息有误");
            return http_resp(conn, false, websocketpp::http::status_code::ok,"场次信息有误");
        }

        //std::cout << req_body << std::endl;
        //查找用户复盘的场次是否存在
        std::string fight_id_str = fight_msg["fight_id"].asString();
        std::string op_type = fight_msg["optype"].asString();
        uint64_t fight_id = atoll(fight_id_str.c_str());
        
        //std::cout << "用户要复盘的场次号为  " << fight_id << std::endl;

        //通过场次id进行相关操作，返回
        if (op_type == "replay")
        {
            _web_ut.select_data_by_fight_id(fight_id, resp);
        }else if (op_type == "delete")
        {
            _web_ut.delete_user_data(fight_id);
        }
        
        resp["result"] = true;
        std::string resp_msg;
        Json_API::serialize(resp, resp_msg);
        conn->set_body(resp_msg);
        conn->append_header("Content-Type", "application/json");
        conn->set_status(websocketpp::http::status_code::ok);
    }

    void data_list(web_server_t::connection_ptr conn)
    {
        
        websocketpp::http::parser::request req = conn->get_request();
        std::string cookie_req = conn->get_request_header("Cookie");
        Json::Value resp;
        
        session_ptr sp = get_session_ptr_from_connect_http(conn);
        if (sp.get() == nullptr)
            return;

        //给session设为永久存在
        //_web_sm.set_session_expire_time(sp->get_ssid(), SESSION_FOREVER);


        // 3. 从数据库中取出用户信息，进行序列化发送给客户端
        if (_web_ut.select_data_rank_by_id(sp->get_user(), resp) == false)
        {
            log_message(NORMAL, "找不到用户历史信息，请重新登录");
            return http_resp(conn, false, websocketpp::http::status_code::ok, "找不到用户信息，请重新登录");
        }

        resp["result"] = true;
        std::string resp_msg;
        Json_API::serialize(resp, resp_msg);
        conn->set_body(resp_msg);
        conn->append_header("Content-Type", "application/json");
        conn->set_status(websocketpp::http::status_code::ok);
    }

    void web_http_callback(websocketpp::connection_hdl hdl)
    {
        //获得请求连接管理指针
        web_server_t::connection_ptr conn = _web_ser.get_con_from_hdl(hdl);
        websocketpp::http::parser::request req = conn->get_request();
        std::string method = req.get_method();
        std::string uri = req.get_uri();

        if (method == "POST" && uri == "/reg")
        {
            return user_register(conn);
        }
        else if (method == "POST" && uri == "/login")
        {
            return user_login(conn);
        }
        else if (method == "GET" && uri == "/userinfo")
        {
            return user_info(conn);
        }
        else if (method == "GET" && uri == "/rank_list")
        {
            return rank_list(conn);
        }
        else if (method == "POST" && uri == "/viewer")
        {
            return viewer_info(conn);
        }
        else if (method == "GET" && uri == "/data_list")
        {
            return data_list(conn);
        }
        else if (method == "POST" && uri == "/replay")
        {
            return replay_info(conn);
        }
        else{
            return file_handle(conn);
        }
    }

    void game_hall_resp(web_server_t::connection_ptr conn, bool result, std::string reason, Json::Value& resp)
    {
        resp["result"] = result;
        resp["reason"] = reason;
        std::string resp_msg;
        Json_API::serialize(resp, resp_msg);
        conn->send(resp_msg);
    }

    session_ptr get_session_ptr_from_connect_ws(web_server_t::connection_ptr& conn)
    {
        //判断用户是否登录
        Json::Value resp;
        resp["optype"] = "hall_ready";
        websocketpp::http::parser::request req = conn->get_request();
        std::string cookie_req = conn->get_request_header("Cookie");
        // 1. 获取请求信息中的Cookie，从Cookie中获取ssid
        if (cookie_req.empty())
        {   
            game_hall_resp(conn, false,"找不到cookie信息，请重新登录", resp);
            return session_ptr();
        }     
        // 1.5. 从cookie中取出ssid
        std::string ssid_str;
        if (!get_ssid_from_cookie(cookie_req, "SSID", ssid_str))
        {
            game_hall_resp(conn, false,"找不到session信息，请重新登录", resp);
            return session_ptr();
        }
        // 2. 在session管理中查找对应的会话信息
        session_ptr sp = _web_sm.get_session_by_ssid(std::stol(ssid_str));
        if (sp.get() == nullptr)
        {
            game_hall_resp(conn, false, "session信息已过期，请重新登录", resp);
            return session_ptr();
        }
        return sp;
    }

    void open_game_hall(web_server_t::connection_ptr& conn){
        
        Json::Value resp;
        resp["optype"] = "hall_ready";
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //判断用户是否重复登录
        if (_web_om.is_in_hall(sp->get_user()) || _web_om.is_in_room(sp->get_user()))
        {   
            return game_hall_resp(conn, false, "该用户已登录", resp);
        }

        //将当前连接加入到游戏大厅
        _web_om.enter_hall(sp->get_user(), conn);

        //给session设为永久存在
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_FOREVER);

        //给客户端响应长连接建立成功
        return game_hall_resp(conn, true, "对弈大厅连接成功", resp);
    }

     void open_game_room(web_server_t::connection_ptr& conn){
        
        Json::Value resp;
        resp["optype"] = "room_ready";
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //判断用户是否重复登录或在其它房间
        if (_web_om.is_in_hall(sp->get_user()) || _web_om.is_in_room(sp->get_user()))
        {   
            return game_hall_resp(conn, false, "该用户已登录", resp);
        }

        //判断玩家的房间是否已经创建完成
        room_ptr rp = _web_rm.get_room_by_uid(sp->get_user());
        if (rp.get() == nullptr)
        {
            return game_hall_resp(conn, false, "房间并未创建", resp);
        }

        //将当前连接加入到在线游戏管理中
        _web_om.enter_room(sp->get_user(), conn);

        //给session设为永久存在
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_FOREVER);

        //给客户端响应进入游戏房间成功
        resp["room_id"] = rp->get_room_id();
        resp["white_id"] = rp->get_white_uid();
        resp["black_id"] = rp->get_black_uid();
        resp["cur_op_id"] = rp->get_cur_op_id();
        resp["uid"] = sp->get_user();
        resp["winner"] = rp->get_winner_uid();
        std::string board_msg = rp->get_board_msg();
        //std::cout << board_msg << std::endl;
        resp["board_msg"] = board_msg.c_str();
        resp["reconn"] = "重新连接成功";
        std::string reconnect;
        Json_API::serialize(resp, reconnect);
        //std::cout << reconnect << std::endl;
        return game_hall_resp(conn, true, "游戏房间连接成功", resp);
    }

    void open_self_create_room(web_server_t::connection_ptr& conn){
        
        Json::Value resp;
        resp["optype"] = "create_room_ready";
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //判断用户是否重复登录
        if (_web_om.is_in_hall(sp->get_user()) || _web_om.is_in_room(sp->get_user()))
        {   
            return game_hall_resp(conn, false, "该用户已登录", resp);
        }

        //将当前连接加入到游戏大厅
        _web_om.enter_hall(sp->get_user(), conn);

        //给session设为永久存在
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_FOREVER);

        //给客户端响应长连接建立成功
        return game_hall_resp(conn, true, "创建房间连接成功", resp);
    }

    void web_open_callback(websocketpp::connection_hdl hdl)
    {
        //获得请求连接管理指针
        web_server_t::connection_ptr conn = _web_ser.get_con_from_hdl(hdl);
        websocketpp::http::parser::request req = conn->get_request();
        std::string uri = req.get_uri();
        //建立对弈大厅的长连接
        if (uri == "/hall"){
            return open_game_hall(conn);
        }
        //建立游戏房间的长连接
        else if (uri == "/room"){
            return open_game_room(conn);
        }
        else if (uri == "/create_room")
        {
            return open_self_create_room(conn);
        }
    }

    void close_game_hall(web_server_t::connection_ptr& conn){
        
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //std::cout << "游戏大厅长连接已经关闭" << std::endl;
        //将玩家从对弈大厅移除
        _web_om.exit_hall(sp->get_user());

        //将session计时器重设
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_TIMEOUT);

    }

    void close_game_room(web_server_t::connection_ptr& conn){
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //将玩家从在线游戏房间管理移除
        _web_om.exit_room(sp->get_user());

        //将session计时器重设
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_TIMEOUT);
        //std::cout<< "从在线管理的游戏房间中退出了，并且计时器重新计时了" << std::endl;

        //将用户从游戏房间移除，房间人为0时，房间自动销毁
        //_web_rm.remove_room_user(sp->get_user());
        //std::cout<< "用户从游戏房间中退出了" << std::endl;

        //当玩家退出后，不是立即把玩家的信息给删掉，因为玩家可能在刷新
        web_server_t::timer_ptr tmp = _web_ser.set_timer(RECONNECTION, \
            std::bind(&web_server::destory_or_reconnection, this, sp->get_user()));         
    }

    void close_create_room(web_server_t::connection_ptr& conn){
        
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //std::cout << "创建房间大厅长连接已经关闭" << std::endl;

        //将玩家从对弈大厅移除
        _web_om.exit_hall(sp->get_user());

        //将session计时器重设
        _web_sm.set_session_expire_time(sp->get_ssid(), SESSION_TIMEOUT);

    }

    void web_close_callback(websocketpp::connection_hdl hdl)
    {
        //获得请求连接管理指针
        web_server_t::connection_ptr conn = _web_ser.get_con_from_hdl(hdl);
        websocketpp::http::parser::request req = conn->get_request();
        std::string uri = req.get_uri();
        //断开对弈大厅的长连接
        if (uri == "/hall"){
            return close_game_hall(conn);
        }
        //断开游戏房间的长连接
        else if(uri == "/room"){
            return close_game_room(conn);
        }
        else if(uri == "/create_room"){
            return close_create_room(conn);
        }
    }

    void get_msg_hall(web_server_t::connection_ptr& conn, web_server_t::message_ptr msg)
    {
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //对请求进行处理 
        std::string req_body = msg->get_payload();
        Json::Value req_msg, resp_msg;
        if (!Json_API::deserialize(req_body, req_msg))
        {
            return game_hall_resp(conn, false, "请求信息有误", resp_msg);
        }
       
        if (!req_msg["optype"].isNull() && req_msg["optype"].asString() == "match_start")
        {
            //开始匹配：将用户移入匹配队列
            _web_mm.add(sp->get_user());
            resp_msg["optype"] = "match_start";

            //当玩家匹配开始，如果一定时间内没有匹配到人，那么就添加一个机器人进入匹配队列
            web_server_t::timer_ptr tmp = _web_ser.set_timer(MATCH_TIME, \
            std::bind(&web_server::join_robot_to_match_queue, this));  
            return game_hall_resp(conn, true, "已加入匹配队列", resp_msg);
        }
        else if (!req_msg["optype"].isNull() && req_msg["optype"].asString() == "match_stop")
        {
            //停止匹配：将用户移除匹配队列
            _web_mm.del(sp->get_user());
            resp_msg["optype"] = "match_stop";
            return game_hall_resp(conn, true, "已停止匹配", resp_msg);
        }

        resp_msg["optype"] = "unknow";
        return game_hall_resp(conn, false, "未知的请求类型", resp_msg);
    }

    void get_msg_room(web_server_t::connection_ptr& conn, web_server_t::message_ptr msg)
    {
        Json::Value req_msg, resp_msg;
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        room_ptr rp = _web_rm.get_room_by_uid(sp->get_user());
        if (rp.get() == nullptr)
        {
            resp_msg["optype"] = "unknow";
            return game_hall_resp(conn, false, "并未创建游戏房间", resp_msg);
        }


        //对请求进行处理 
        std::string req_body = msg->get_payload();
        if (!Json_API::deserialize(req_body, req_msg))
        {
            return game_hall_resp(conn, false, "请求信息有误", resp_msg);
        }

        rp->handle_request(req_msg);
    }

    void get_msg_create_room(web_server_t::connection_ptr& conn, web_server_t::message_ptr msg)
    {
        session_ptr sp = get_session_ptr_from_connect_ws(conn);
        if (sp.get() == nullptr) return;

        //对请求进行处理 
        std::string req_body = msg->get_payload();
        Json::Value req_msg, resp_msg;
        if (!Json_API::deserialize(req_body, req_msg))
        {
            return game_hall_resp(conn, false, "请求信息有误", resp_msg);
        }

        //std::cout << "收到来自独自创建房间页面的请求，正在处理请求" << std::endl;
        if (!req_msg["optype"].isNull() && req_msg["optype"].asString() == "create_start")
        {
            //开始匹配：将用户移入匹配队列
            _web_mm.self_add(req_msg["room_num"].asString(), sp->get_user());
            resp_msg["optype"] = "create_start";
            resp_msg["room_num"] = req_msg["room_num"];
            return game_hall_resp(conn, true, "正在创建", resp_msg);
        }
        else if (!req_msg["optype"].isNull() && req_msg["optype"].asString() == "create_stop")
        {
            //停止匹配：将用户移除匹配队列
            _web_mm.self_del(req_msg["room_num"].asString(), sp->get_user());
            resp_msg["optype"] = "create_stop";
            return game_hall_resp(conn, true, "已停止创建", resp_msg);
        }

        resp_msg["optype"] = "unknow";
        return game_hall_resp(conn, false, "未知的请求类型", resp_msg);
    }

    void web_message_callback(websocketpp::connection_hdl hdl, web_server_t::message_ptr msg)
    {
        //获得请求连接管理指针
        web_server_t::connection_ptr conn = _web_ser.get_con_from_hdl(hdl);
        websocketpp::http::parser::request req = conn->get_request();
        std::string uri = req.get_uri();
        //收到对弈大厅的请求
        if (uri == "/hall"){
            return get_msg_hall(conn, msg);
        }
        //收到游戏房间的请求
        else if (uri == "/room"){
            return get_msg_room(conn, msg);
        }
        else if (uri == "/create_room"){
            return get_msg_create_room(conn, msg);
        }
    }
};